// ToolParam.h: interface for the CToolParam class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_TOOLPARAM_H__FEECFDB3_81E7_45A6_B224_9AEB0B3652A5__INCLUDED_)
#define AFX_TOOLPARAM_H__FEECFDB3_81E7_45A6_B224_9AEB0B3652A5__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000


class CXMLSettings;
class CToolParam  
{
public:
	CToolParam(LPCTSTR pszName = _T(""));
	virtual ~CToolParam();
	virtual void Serialize(CXMLSettings& xml);

	inline BOOL SetVal(int iVal)
	{
		if (m_strArray.GetSize())
		{
			if (m_pValue == NULL)
			{
				m_nValType = VT_INT|VT_ARRAY;
				m_pValue = new int;
				m_szValue = sizeof(int);
			}
			
			if (iVal < 0)
			{
				*(int*)m_pValue = 0/*-1*/;
				return FALSE;
			}

			if (iVal < m_strArray.GetSize())
			{
				*(int*)m_pValue = iVal;
				return TRUE;
			}

			*(int*)m_pValue = 0/*-1*/;
			return FALSE;
		}
		
		if (m_pValue != NULL)
		{
			if (m_nValType == VT_INT)
			{
				*(int*)m_pValue = iVal;
				return TRUE;
			}

			delete m_pValue;
		}
	
		m_pValue = new int(iVal);
		m_nValType = VT_INT;
		m_szValue = sizeof(int);
		return TRUE;
	}

	inline BOOL SetVal(UINT uiVal)
	{
		if (m_pValue != NULL)
		{
			if (m_nValType == VT_UINT)
			{
				*(UINT*)m_pValue = uiVal;
				return TRUE;
			}

			delete m_pValue;
		}

		m_pValue = new UINT(uiVal);
		m_nValType = VT_UINT;
		m_szValue = sizeof(UINT);
		return TRUE;
	}

	inline BOOL SetVal(short sVal)
	{
		if (m_pValue != NULL)
		{
			if (m_nValType == VT_I2)
			{
				*(short*)m_pValue = sVal;
				return TRUE;
			}

			delete m_pValue;
		}

		m_pValue = new short(sVal);
		m_nValType = VT_I2;
		m_szValue = sizeof(short);
		return TRUE;
	}

	inline BOOL SetVal(long lVal)
	{
		if (m_pValue != NULL)
		{
			if (m_nValType == VT_I4)
			{
				*(long*)m_pValue = lVal;
				return TRUE;
			}
			
			delete m_pValue;
		}
		
		m_pValue = new long(lVal);
		m_nValType = VT_I4;
		m_szValue = sizeof(long);
		return TRUE;
	}

	inline BOOL SetVal(WORD wVal)
	{
		if (m_pValue != NULL)
		{
			if (m_nValType == VT_UI2)
			{
				*(WORD*)m_pValue = wVal;
				return TRUE;
			}
			
			delete m_pValue;
		}
		
		m_pValue = new WORD(wVal);
		m_nValType = VT_UI2;
		m_szValue = sizeof(WORD);
		return TRUE;
	}

	inline BOOL SetVal(DWORD dwVal)
	{
		if (m_pValue != NULL)
		{
			if (m_nValType == VT_UI4)
			{
				*(DWORD*)m_pValue = dwVal;
				return TRUE;
			}
			
			delete m_pValue;
		}
		
		m_pValue = new DWORD(dwVal);
		m_nValType = VT_UI4;
		m_szValue = sizeof(DWORD);
		return TRUE;
	}

	inline BOOL SetVal(float fVal)
	{
		if (m_pValue != NULL)
		{
			if (m_nValType == VT_R4)
			{
				*(float*)m_pValue = fVal;
				return TRUE;
			}

			delete m_pValue;
		}

		m_pValue = new float(fVal);
		m_nValType = VT_R4;
		m_szValue = sizeof(float);
		return TRUE;
	}

	inline BOOL SetVal(double dVal)
	{
		if (m_pValue != NULL)
		{
			if (m_nValType == VT_R8)
			{
				*(double*)m_pValue = dVal;
				return TRUE;
			}

			delete m_pValue;
		}

		m_pValue = new double(dVal);
		m_nValType = VT_R8;
		m_szValue = sizeof(double);
		return TRUE;
	}

	inline BOOL SetVal(LPCTSTR pszVal)
	{
		if (m_nValType == VT_BSTR)
		{
			m_strArray[0] = pszVal;
			return TRUE;
		}

		int n = m_strArray.GetSize();
		if (n)
		{
			if (m_pValue == NULL)
			{
				m_pValue = new int;
				m_nValType = VT_INT|VT_ARRAY;
				m_szValue = sizeof(int);
			}
			
			int i = 0;
			for ( ; i < n; i++)
			{
				if (m_strArray[i] == pszVal)
					break;
			}
			
			if (i == n)
			{
				*(int*)m_pValue = 0/*-1*/;
				return FALSE;
			}
			
			*(int*)m_pValue = i;
			return TRUE;
		}

		if (m_pValue != NULL)
			delete m_pValue;

		m_strArray.Add(pszVal);
		m_nValType = VT_BSTR;
		m_szValue = 0;
		return TRUE;
	}

	inline BOOL SetVal(LPBYTE pVal, DWORD dwBytes)
	{
		if (m_pValue != NULL)
			delete m_pValue;

		m_pValue = new BYTE[dwBytes];
		memcpy(m_pValue, pVal, dwBytes);
		m_nValType = VT_BYREF;
		m_szValue = dwBytes;
		return TRUE;
	}

	CString GetString();
	
	void Init(CToolParam* pTP)
	{
		m_strType = pTP->m_strType;		
		m_strName = pTP->m_strName;	
		m_strUnit = pTP->m_strUnit;	
		m_nValType = pTP->m_nValType;		
		m_strDesc = pTP->m_strDesc;		
		m_szValue = pTP->m_szValue;
		m_pValue = new BYTE[m_szValue];
		memcpy(m_pValue, pTP->m_pValue, m_szValue);
		m_lTop = pTP->m_lTop;			
		m_lBottom = pTP->m_lBottom;		
		m_strComment = pTP->m_strComment;
		m_lSave = pTP->m_lSave;		
	    m_bDisplayPrint = pTP->m_bDisplayPrint; 
		for (int i = 0; i < pTP->m_strArray.GetSize();i++)
			m_strArray.Add(pTP->m_strArray.GetAt(i));
	}
	CString SetString(LPCTSTR pszText);

public:
	CString		m_strType;		// Measurement type
	CString		m_strName;		// Param name
	CString		m_strUnit;		// Param unit
	VARTYPE		m_nValType;		// Value type
	CString		m_strDesc;		// Description
	void*		m_pValue;		// Value pointer
	size_t		m_szValue;		// Value size
	CStringArray	m_strArray;	// Enum values
	long		m_lTop;			// Top depth
	long		m_lBottom;		// Bottom depth
	CString		m_strComment;	// Comment
	long		m_lSave;		// Save counter
	DWORD       m_bDisplayPrint;       // Print or not
};

typedef CList<CToolParam*, CToolParam*>	CTPList;

class CToolParams
{
public:
	CToolParams() {}
	~CToolParams()
	{
		while (m_tpList.GetCount())
			delete m_tpList.RemoveHead();
	}

	virtual void Serialize(CXMLSettings& xml, BOOL bNew = FALSE);
	BOOL WriteTo(CXMLSettings& xml, long lDepth);

	BOOL WriteToFile(CFile* pFile);
	BOOL ReadFromFile(CFile* pFile);

	BOOL WriteToStream(IStreamPtr& stream);
	BOOL ReadFromStream(IStreamPtr& stream);

	void ClearParams()
	{
		while (m_tpList.GetCount())
			delete m_tpList.RemoveHead();
	}

	CToolParam* FindParam (LPCTSTR lpszName) const
	{
		for (POSITION pos = m_tpList.GetHeadPosition (); pos != NULL;)
		{
			CToolParam* pTP = m_tpList.GetNext (pos);			
			if (pTP->m_strName == lpszName)
				return pTP;
		}
		
		return NULL;
	}

	CToolParam* GetParam (LPCTSTR lpszName)
	{
		for (POSITION pos = m_tpList.GetHeadPosition (); pos != NULL;)
		{
			CToolParam* pTP = m_tpList.GetNext (pos);			
			if (pTP->m_strName == lpszName)
				return pTP;
		}
		
		CToolParam* pTP = new CToolParam(lpszName);
		m_tpList.AddTail(pTP);
		return pTP;
	}

	BOOL GetParam(LPCTSTR lpszName, int& iVal)
	{
		CToolParam* pTP = FindParam(lpszName);
		if (pTP != NULL)
		{
			if (pTP->m_nValType == VT_INT)
			{
				iVal = *(int*)pTP->m_pValue;
				return TRUE;
			}

			if (pTP->m_nValType & VT_ARRAY)
			{
				iVal = *(int*)pTP->m_pValue;
				if (iVal < 0)
					return FALSE;
				
				if (iVal < pTP->m_strArray.GetSize())
					return TRUE;
				
				*(int*)pTP->m_pValue = -1;
				iVal = -1;
				return FALSE;
			}
		}

		return FALSE;
	}

	BOOL GetParam(LPCTSTR lpszName, UINT& uiVal)
	{
		CToolParam* pTP = FindParam(lpszName);
		if (pTP != NULL)
		{
			if (pTP->m_nValType == VT_UINT)
			{
				uiVal = *(UINT*)pTP->m_pValue;
				return TRUE;
			}
		}
		
		return FALSE;
	}

	BOOL GetParam(LPCTSTR lpszName, short& sVal)
	{
		CToolParam* pTP = FindParam(lpszName);
		if (pTP != NULL)
		{
			if (pTP->m_nValType == VT_I2)
			{
				sVal = *(short*)pTP->m_pValue;
				return TRUE;
			}
		}
		
		return FALSE;
	}

	BOOL GetParam(LPCTSTR lpszName, long& lVal)
	{
		CToolParam* pTP = FindParam(lpszName);
		if (pTP != NULL)
		{
			if (pTP->m_nValType == VT_I4)
			{
				lVal = *(long*)pTP->m_pValue;
				return TRUE;
			}

			if (pTP->m_nValType & VT_ARRAY)
			{
				lVal = *(int*)pTP->m_pValue;
				if (lVal < 0)
					return FALSE;
				
				if (lVal < pTP->m_strArray.GetSize())
					return TRUE;
				
				*(int*)pTP->m_pValue = -1;
				lVal = -1;
				return FALSE;
			}
		}
		
		return FALSE;
	}

	BOOL GetParam(LPCTSTR lpszName, WORD& wVal)
	{
		CToolParam* pTP = FindParam(lpszName);
		if (pTP != NULL)
		{
			if (pTP->m_nValType == VT_UI2)
			{
				wVal = *(WORD*)pTP->m_pValue;
				return TRUE;
			}
		}
		
		return FALSE;
	}

	BOOL GetParam(LPCTSTR lpszName, DWORD& dwVal)
	{
		CToolParam* pTP = FindParam(lpszName);
		if (pTP != NULL)
		{
			if (pTP->m_nValType == VT_UI4)
			{
				dwVal = *(DWORD*)pTP->m_pValue;
				return TRUE;
			}
		}
		
		return FALSE;
	}

	BOOL GetParam(LPCTSTR lpszName, float& fVal)
	{
		CToolParam* pTP = FindParam(lpszName);
		if (pTP != NULL)
		{
			if (pTP->m_nValType == VT_R4)
			{
				fVal = *(float*)pTP->m_pValue;
				return TRUE;
			}
		}
		
		return FALSE;
	}

	BOOL GetParam(LPCTSTR lpszName, double& dVal)
	{
		CToolParam* pTP = FindParam(lpszName);
		if (pTP != NULL)
		{
			if (pTP->m_nValType == VT_R8)
			{
				dVal = *(double*)pTP->m_pValue;
				return TRUE;
			}
		}
		
		return FALSE;
	}

	BOOL GetParam(LPCTSTR lpszName, CString& sVal)
	{
		CToolParam* pTP = FindParam(lpszName);
		if (pTP != NULL)
		{
			if (pTP->m_nValType == VT_BSTR)
			{
				if (pTP->m_strArray.GetSize())
				{
					sVal = pTP->m_strArray.GetAt(0);
					return TRUE;
				}
				
				return FALSE;
			}

			if (pTP->m_nValType & VT_ARRAY)
			{
				int i = *(int*)pTP->m_pValue;
				if (i < 0 || i>= pTP->m_strArray.GetSize())
				{
					sVal.Empty();
					return FALSE;
				}

				sVal = pTP->m_strArray[i];
				return TRUE;
			}
		}
		
		return FALSE;
	}

	DWORD GetParam(LPCTSTR lpszName, LPBYTE pVal)
	{
		CToolParam* pTP = FindParam(lpszName);
		if (pTP != NULL)
		{
			if (pTP->m_nValType == VT_BYREF)
			{
				if (AfxIsValidAddress(pVal, pTP->m_szValue))
				{
					memcpy(pVal, pTP->m_pValue, pTP->m_szValue);
					return pTP->m_szValue;
				}
			}
		}

		return 0;
	}

	inline void SaveFirst()
	{
		for (POSITION pos = m_tpList.GetHeadPosition(); pos != NULL; )
		{
			CToolParam* pTP = m_tpList.GetNext(pos);
			pTP->m_lSave = 1;
		}
	}

	inline void Save()
	{
		for (POSITION pos = m_tpList.GetHeadPosition(); pos != NULL; )
		{
			CToolParam* pTP = m_tpList.GetNext(pos);
			InterlockedIncrement(&pTP->m_lSave);
		}
	}

public:
	CString		m_strTool;
	CTPList		m_tpList;

};

typedef CList<CToolParams*, CToolParams*>	CTPTree;

#endif // !defined(AFX_TOOLPARAM_H__FEECFDB3_81E7_45A6_B224_9AEB0B3652A5__INCLUDED_)
